﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Xml.Linq;
using System.IO;
using System.Reflection;
using CommonInteractive.Config;
using devtm.CommonInteractive.Config;
using CommonInteractive.Commands.Models;

namespace CommonInteractive.Config
{

    public abstract class Config
    {


        public const string Initializer = "Initializer";
        public const string Wizard = "Wizard";

                
        public Config()
        {
            Assemblies = new AssemblyRepository();            
        }


        public IOutput Log { get; set; }


        public static XElement GetXElement(string filename)
        {
            FileInfo file = null;

            if (File.Exists(filename))
                file = new FileInfo(filename);

            XElement a = System.Xml.Linq.XElement.Load(filename);
            return a;
        }

        public static Configuration GetConfiguration(string filename)
        {
            FileInfo file = null;

            if (File.Exists(filename))
                file = new FileInfo(filename);

            var i = new ExeConfigurationFileMap() { ExeConfigFilename = file.FullName };

            return ConfigurationManager.OpenMappedExeConfiguration(i, ConfigurationUserLevel.None);

        }


        public IEnumerable<Assembly> Assemblies { get; set; }


        public IEnumerable<Type> GetTypes(Type search)
        {

            string a = search.Assembly.FullName;
            AssemblyName c = search.Assembly.GetName();

            AssemblyRepository b = Assemblies as AssemblyRepository;

            foreach (var Ass in b.SelectOnlyWithReference(c, false))
                foreach (Type type in GetTypes(Ass))
                {

                    if (search.IsInterface)
                        if (type.GetInterface(search.FullName, false) != null)
                            yield return type;

                        else
                            if (type.IsSubclassOf(search))
                                yield return type;

                }

        }


        public Type[] GetTypes(Assembly ass)
        {
            Type[] types = null;
            try
            {
                types = ass.GetTypes();
            }
            catch (ReflectionTypeLoadException ex)
            {

                var ll = ex.LoaderExceptions.Select(c => c.Message).Distinct();

                foreach (string mm in ll)
                    this.Log.WriteLine(string.Format("Can't be parsed type from the {0} assembly because : {1}", ass.FullName, mm));

                types = ex.Types.Where(c => c != null).ToArray();

            }
            return types;
        }


        public static IGenerate Create(Type mytype)
        {
            return Activator.CreateInstance(mytype) as IGenerate;
        }


        public IScriptDescriptor ScriptDescriptor { get; set; }


    }
}
